﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AAA.TradeLanguage.Data;
using AAA.DesignPattern.Singleton;
using AAA.DataSource;

namespace AAA.TradeLanguage
{
    public class DefaultTradingRule : ITradingRule
    {
        private Dictionary<string, List<TradeSymbol>> _dicSignalMapping;
        private Dictionary<string, ContractInfo> _dicContractMapping;
        private Dictionary<string, int> _dicSignalMultiple;

        private float _fPreviousAtMoneyPrice;
        private string _strCurrentDate;

        public DefaultTradingRule()
        {
            _dicSignalMapping = new Dictionary<string, List<TradeSymbol>>();
            _dicSignalMultiple = new Dictionary<string, int>();
            _dicContractMapping = new Dictionary<string, ContractInfo>();

            _fPreviousAtMoneyPrice = 0;
            _strCurrentDate = "19000101";
        }


        #region ITradingRule 成員

        public void AddContractInfo(string strParamName, ContractInfo contractInfo)
        {
            try
            {
                if (_dicContractMapping.ContainsKey(strParamName))
                {
                    _dicContractMapping[strParamName] = contractInfo;
                }
                else
                {
                    _dicContractMapping.Add(strParamName, contractInfo);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void AddSignalSymbolMapping(string strSignalName, TradeSymbol tradeSymbol)
        {
            List<TradeSymbol> lstTradeSymbol;
            try
            {
                if (_dicSignalMapping.ContainsKey(strSignalName) == false)
                {
                    lstTradeSymbol = new List<TradeSymbol>();
                    _dicSignalMapping.Add(strSignalName, lstTradeSymbol);
                }
                else
                {
                    lstTradeSymbol = _dicSignalMapping[strSignalName];
                }

                if (lstTradeSymbol.Contains(tradeSymbol) == false)
                {
                    lstTradeSymbol.Add(tradeSymbol);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void SetSignalMultiple(string strSignalName, int iMultiple)
        {
            try
            {
                if (_dicSignalMultiple.ContainsKey(strSignalName))
                    _dicSignalMultiple[strSignalName] = iMultiple;
                else
                    _dicSignalMultiple.Add(strSignalName, iMultiple);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public List<TradeSymbol> GetTradeSymbol(string strSignalName)
        {
            return _dicSignalMapping.ContainsKey(strSignalName)
                    ? _dicSignalMapping[strSignalName]
                    : new List<TradeSymbol>();
        }

        public TradeInfo[] CreateOrder(string strSignalName)
        {
            TradeInfo[] orderInfos = new TradeInfo[0];
            ContractInfo contractInfo = null;
            List<TradeSymbol> lstTradeSymbol;
            
            try
            {
                if (_dicSignalMapping == null)
                    return orderInfos;

                if (_dicSignalMapping.ContainsKey(strSignalName) == false)
                    return orderInfos;

                lstTradeSymbol = _dicSignalMapping[strSignalName];
                orderInfos = new TradeInfo[lstTradeSymbol.Count];

                for(int i = 0; i < lstTradeSymbol.Count; i++)
                {
                    orderInfos[i] = new TradeInfo();
                    orderInfos[i].IsDayTrade = lstTradeSymbol[i].IsDayTrade;
                    orderInfos[i].OrderDirection = lstTradeSymbol[i].OrderDirection;
                    orderInfos[i].Volume = lstTradeSymbol[i].Volume;
                    switch (lstTradeSymbol[i].ContractType)
                    {
                        case ContractTypeEnum.Hot:

                            contractInfo = (ContractInfo)(_dicContractMapping.ContainsKey(DataSourceConstants.HOT_CONTRACT)
                                                            ?   _dicContractMapping[DataSourceConstants.HOT_CONTRACT]
                                                            :   SystemParameter.Parameter[DataSourceConstants.HOT_CONTRACT]);
                            orderInfos[i].Year = contractInfo.Year;
                            orderInfos[i].Month = contractInfo.Month;
                            break;
                        case ContractTypeEnum.Next:
                            contractInfo = (ContractInfo)(_dicContractMapping.ContainsKey(DataSourceConstants.NEXT_MONTH_CONTRACT)
                                                            ? _dicContractMapping[DataSourceConstants.NEXT_MONTH_CONTRACT]
                                                            : SystemParameter.Parameter[DataSourceConstants.NEXT_MONTH_CONTRACT]); 
                                                            //SystemParameter.Parameter[DataSourceConstants.NEXT_MONTH_CONTRACT];
                            orderInfos[i].Year = contractInfo.Year;
                            orderInfos[i].Month = contractInfo.Month;
                            break;
                        case ContractTypeEnum.FirstQ:
                            break;
                        case ContractTypeEnum.SecondQ:
                            break;
                        case ContractTypeEnum.ThirdQ:
                            break;
                    }

                    orderInfos[i].SymbolType = lstTradeSymbol[i].SymbolType;
                    switch (lstTradeSymbol[i].SymbolType)
                    {
                        case SymbolTypeEnum.Futures:
                            orderInfos[i].SymbolName = "台指";
                            break;
                        case SymbolTypeEnum.MiniFutures:
                            orderInfos[i].SymbolName = "小台";
                            break;
                        case SymbolTypeEnum.Call:
                            orderInfos[i].SymbolName = "買權";
                            break;
                        case SymbolTypeEnum.Put:
                            orderInfos[i].SymbolName = "賣權";
                            break;
                    }

                    if ((lstTradeSymbol[i].SymbolType == SymbolTypeEnum.Call) ||
                       (lstTradeSymbol[i].SymbolType == SymbolTypeEnum.Put))
                    {
                        switch (lstTradeSymbol[i].ExecutePriceType)
                        {
                            case ExecutePriceTypeEnum.AtTheMoney:
                                if (lstTradeSymbol[i].SymbolType == SymbolTypeEnum.Call)
                                {                                    
                                    contractInfo = (ContractInfo)(_dicContractMapping.ContainsKey(DataSourceConstants.CALL_AT_THE_MONEY)
                                                            ?   _dicContractMapping[DataSourceConstants.CALL_AT_THE_MONEY]
                                                            :   SystemParameter.Parameter[DataSourceConstants.CALL_AT_THE_MONEY]);
                                    //SystemParameter.Parameter[DataSourceConstants.CALL_AT_THE_MONEY]);
                                }
                                else
                                {
                                    contractInfo = (ContractInfo)(_dicContractMapping.ContainsKey(DataSourceConstants.PUT_AT_THE_MONEY)
                                                                    ? _dicContractMapping[DataSourceConstants.PUT_AT_THE_MONEY]
                                                                    : SystemParameter.Parameter[DataSourceConstants.PUT_AT_THE_MONEY]);
                                    //((ContractInfo)SystemParameter.Parameter[DataSourceConstants.PUT_AT_THE_MONEY]);
                                }
                                break;
                            case ExecutePriceTypeEnum.InTheMoney:
                                if (lstTradeSymbol[i].SymbolType == SymbolTypeEnum.Call)
                                {
                                    contractInfo = ((ContractInfo)(_dicContractMapping.ContainsKey(DataSourceConstants.CALL_AT_THE_MONEY)
                                                                    ? _dicContractMapping[DataSourceConstants.CALL_AT_THE_MONEY]
                                                                    : SystemParameter.Parameter[DataSourceConstants.CALL_AT_THE_MONEY])).Clone();
                                        //((ContractInfo)SystemParameter.Parameter[DataSourceConstants.CALL_AT_THE_MONEY]).Clone();
                                    contractInfo.ExecutePrice = SymbolUtil.ShiftExecutePrice(contractInfo.ExecutePrice, -1 * lstTradeSymbol[i].ExecutePriceZone);
                                }
                                else
                                {
                                    contractInfo = (ContractInfo)(_dicContractMapping.ContainsKey(DataSourceConstants.PUT_AT_THE_MONEY)
                                                            ? _dicContractMapping[DataSourceConstants.PUT_AT_THE_MONEY]
                                                            : SystemParameter.Parameter[DataSourceConstants.PUT_AT_THE_MONEY]);
                                        
                                        //((ContractInfo)SystemParameter.Parameter[DataSourceConstants.PUT_AT_THE_MONEY]);
                                    contractInfo.ExecutePrice = SymbolUtil.ShiftExecutePrice(contractInfo.ExecutePrice, lstTradeSymbol[i].ExecutePriceZone);
                                }

                                break;
                            case ExecutePriceTypeEnum.OutOfTheMoney:
                                if (lstTradeSymbol[i].SymbolType == SymbolTypeEnum.Call)
                                {
                                    contractInfo = ((ContractInfo)(_dicContractMapping.ContainsKey(DataSourceConstants.CALL_AT_THE_MONEY)
                                                            ? _dicContractMapping[DataSourceConstants.CALL_AT_THE_MONEY]
                                                            : SystemParameter.Parameter[DataSourceConstants.CALL_AT_THE_MONEY])).Clone();
                                    //((ContractInfo)SystemParameter.Parameter[DataSourceConstants.CALL_AT_THE_MONEY]).Clone();
                                    contractInfo.ExecutePrice = SymbolUtil.ShiftExecutePrice(contractInfo.ExecutePrice, lstTradeSymbol[i].ExecutePriceZone);
                                }
                                else
                                {
                                    contractInfo = (ContractInfo)(_dicContractMapping.ContainsKey(DataSourceConstants.PUT_AT_THE_MONEY)
                                                                    ? _dicContractMapping[DataSourceConstants.PUT_AT_THE_MONEY]
                                                                    : SystemParameter.Parameter[DataSourceConstants.PUT_AT_THE_MONEY]);
                                    //((ContractInfo)SystemParameter.Parameter[DataSourceConstants.PUT_AT_THE_MONEY]);
                                    contractInfo.ExecutePrice = SymbolUtil.ShiftExecutePrice(contractInfo.ExecutePrice, -1 * lstTradeSymbol[i].ExecutePriceZone);
                                }

                                break;
                        }

                        orderInfos[i].ExecutePrice = contractInfo.ExecutePrice;
                        if (lstTradeSymbol[i].Slippage < 0)
                        {
                            orderInfos[i].Price = -1;
                        }
                        else
                        {
                            if (lstTradeSymbol[i].OrderDirection == OrderDirectionEnum.Buy)
                            {

                                orderInfos[i].Price = ((SystemParameter.Parameter[Enum.GetName(typeof(SymbolTypeEnum), contractInfo.SymbolType) + "_" +
                                                                                contractInfo.Year + "_" +
                                                                                contractInfo.Month + "_" +
                                                                                contractInfo.ExecutePrice]) == null
                                                                                ?   (float)-1
                                                                                : (float)SystemParameter.Parameter[Enum.GetName(typeof(SymbolTypeEnum), contractInfo.SymbolType) + "_" +
                                                                                contractInfo.Year + "_" +
                                                                                contractInfo.Month + "_" +
                                                                                contractInfo.ExecutePrice]) + lstTradeSymbol[i].Slippage;

 
                            }
                            else
                            {
                                orderInfos[i].Price = ((SystemParameter.Parameter[Enum.GetName(typeof(SymbolTypeEnum), contractInfo.SymbolType) + "_" +
                                                                                contractInfo.Year + "_" +
                                                                                contractInfo.Month + "_" +
                                                                                contractInfo.ExecutePrice]) == null
                                                                                ? (float)-1
                                                                                : (float)SystemParameter.Parameter[Enum.GetName(typeof(SymbolTypeEnum), contractInfo.SymbolType) + "_" +
                                                                                contractInfo.Year + "_" +
                                                                                contractInfo.Month + "_" +
                                                                                contractInfo.ExecutePrice]) - lstTradeSymbol[i].Slippage;
                            }
                        }                                

                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return orderInfos;
        }

        private void SetContractInfo(string strContractName, ContractInfo contractInfo)
        {
            if (_dicContractMapping.ContainsKey(strContractName))
                _dicContractMapping[strContractName] = contractInfo;
            else
                _dicContractMapping.Add(strContractName, contractInfo);
        }

        public void CreateBasicContractInfo(DateTime dtNow, float fCurrentPrice)
        {
            float fAtTheMoneyPrice;
            ContractInfo hotContract;
            ContractInfo optionsContract;
            ContractInfo atMoneyContract;

            try
            {
                if (dtNow.ToString("yyyyMMdd") != _strCurrentDate)
                {
                    _strCurrentDate = dtNow.ToString("yyyyMMdd");
                    hotContract = SymbolUtil.HotContract(dtNow);
                    SetContractInfo(DataSourceConstants.HOT_CONTRACT, hotContract);
                    SetContractInfo(DataSourceConstants.NEXT_MONTH_CONTRACT, SymbolUtil.NextMonthContract(hotContract));
                }

                fAtTheMoneyPrice = SymbolUtil.AtTheMoneyPrice(fCurrentPrice);

                if (fAtTheMoneyPrice != _fPreviousAtMoneyPrice)
                {
                    // Generate Call Contract;
                    atMoneyContract = GetContractInfo(DataSourceConstants.HOT_CONTRACT).Clone();
                    atMoneyContract.ExecutePrice = fAtTheMoneyPrice;
                    atMoneyContract.SymbolType = SymbolTypeEnum.Call;
                    SetContractInfo(DataSourceConstants.CALL_AT_THE_MONEY, atMoneyContract);                    

                    optionsContract = atMoneyContract.Clone();
                    optionsContract.ExecutePrice = SymbolUtil.ShiftExecutePrice(fAtTheMoneyPrice, -1);
                    SetContractInfo(DataSourceConstants.CALL_IN_THE_MONEY, optionsContract);

                    optionsContract = atMoneyContract.Clone();
                    optionsContract.ExecutePrice = SymbolUtil.ShiftExecutePrice(fAtTheMoneyPrice, 1);
                    SetContractInfo(DataSourceConstants.CALL_OUT_OF_THE_MONEY, optionsContract);

                    // Generate Put Contract;
                    atMoneyContract = GetContractInfo(DataSourceConstants.HOT_CONTRACT).Clone();
                    atMoneyContract.ExecutePrice = fAtTheMoneyPrice;
                    atMoneyContract.SymbolType = SymbolTypeEnum.Put;
                    SetContractInfo(DataSourceConstants.PUT_AT_THE_MONEY, atMoneyContract);

                    optionsContract = atMoneyContract.Clone();
                    optionsContract.ExecutePrice = SymbolUtil.ShiftExecutePrice(fAtTheMoneyPrice, 1);
                    SetContractInfo(DataSourceConstants.PUT_IN_THE_MONEY, optionsContract);

                    optionsContract = atMoneyContract.Clone();
                    optionsContract.ExecutePrice = SymbolUtil.ShiftExecutePrice(fAtTheMoneyPrice, -1);
                    SetContractInfo(DataSourceConstants.PUT_OUT_OF_THE_MONEY, optionsContract);
                    _fPreviousAtMoneyPrice = fAtTheMoneyPrice;
                }

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public ContractInfo GetContractInfo(string strContractName)
        {
            try
            {
                return _dicContractMapping.ContainsKey(strContractName)
                        ? _dicContractMapping[strContractName]
                        : (ContractInfo)SystemParameter.Parameter[strContractName];
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #endregion
    }
}
